/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package src;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Oksana_Moroz
 */
public class Pr1_2 {

    public static double calculateSin(final int n, int numThreads)
            throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
        List<Future<Double>> partSums = new ArrayList<>();

        int all = 2 * n + 1;
        int assignment = (all % numThreads == 0) ? (all / numThreads)
                : (all / numThreads + 1);
        int given = -n;
        for (int i = 0; i < numThreads; i++) {
            final int start = given;
            final int end = given + assignment;
            partSums.add(executorService.submit(new Callable<Double>() {
                @Override
                public Double call() throws Exception {
                    double s = 0;
                    for (int i = start; i < Math.min(end, n + 1); i++) {
                        s += Math.sin(i);
                    }
                    return s;
                }
            }));
            given = end;
        }
        
        
        double sum = 0;
        for (int i = 0; i < numThreads; i++) {
            sum += partSums.get(i).get();
        }
        executorService.shutdown();
        return sum;
    }

    public static void testOptimalNumThreads(int n) throws InterruptedException, ExecutionException {
        long min = Long.MAX_VALUE;
        int numThreads = Integer.MAX_VALUE;
        for (int i = 1; i < 100; i++) {
            long start = System.currentTimeMillis();
            calculateSin(n, i);
            long end = System.currentTimeMillis();
            long diff = end - start;
            if (diff < min) {
                min = diff;
                numThreads = i;
            }
        }
        System.out.println("The most optimal numThreads with executor = "
                + numThreads + ", time = " + min);
    }

    public static void main(String[] args) {
        try {
            System.out.println(calculateSin(10, 5));
            testOptimalNumThreads(10000);
        } catch (InterruptedException | ExecutionException ex) {
            Logger.getLogger(Pr1_2.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}